package com.datagateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 限流管理器
 * 负责实现多种限流算法，包括令牌桶、漏桶、滑动窗口等
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class RateLimiterManager {

    private static final Logger logger = LoggerFactory.getLogger(RateLimiterManager.class);

    @Autowired
    private AlertManager alertManager;

    /**
     * 限流统计
     */
    private final AtomicLong totalRequests = new AtomicLong(0);
    private final AtomicLong totalAllowedRequests = new AtomicLong(0);
    private final AtomicLong totalRejectedRequests = new AtomicLong(0);
    private final AtomicLong totalRateLimitViolations = new AtomicLong(0);

    /**
     * 限流配置
     */
    private boolean rateLimitingEnabled = true;
    private String defaultAlgorithm = "TOKEN_BUCKET";
    private int defaultCapacity = 1000;
    private int defaultRefillRate = 100;
    private int defaultWindowSize = 60;
    private int defaultMaxRequests = 1000;

    /**
     * 限流器存储
     */
    private final Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
    private final Map<String, RateLimitConfig> rateLimitConfigs = new ConcurrentHashMap<>();

    /**
     * 执行器
     */
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, r -> {
        Thread t = new Thread(r, "rate-limiter-manager");
        t.setDaemon(true);
        return t;
    });

    /**
     * 初始化限流管理器
     */
    public void initialize() {
        try {
            // 启动限流监控任务
            startRateLimitMonitoringTask();
            
            logger.info("限流管理器初始化成功");
            
        } catch (Exception e) {
            logger.error("限流管理器初始化失败", e);
            alertManager.sendSystemErrorAlert("限流管理器初始化失败", e.getMessage());
        }
    }

    /**
     * 停止限流管理器
     */
    public void stop() {
        try {
            scheduler.shutdown();
            if (!scheduler.awaitTermination(30, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
            
            logger.info("限流管理器停止成功");
            
        } catch (Exception e) {
            logger.error("限流管理器停止失败", e);
        }
    }

    /**
     * 创建限流器
     * 
     * @param key 限流键
     * @param algorithm 限流算法
     * @param capacity 容量
     * @param refillRate 填充速率
     * @param windowSize 窗口大小
     * @param maxRequests 最大请求数
     * @return 是否创建成功
     */
    public boolean createRateLimiter(String key, String algorithm, int capacity, 
                                   int refillRate, int windowSize, int maxRequests) {
        if (!rateLimitingEnabled) {
            logger.debug("限流已禁用，跳过限流器创建: {}", key);
            return false;
        }

        try {
            RateLimiter rateLimiter = createRateLimiterInstance(algorithm, capacity, refillRate, windowSize, maxRequests);
            if (rateLimiter == null) {
                logger.error("创建限流器失败，不支持的算法: {}", algorithm);
                return false;
            }

            rateLimiters.put(key, rateLimiter);
            
            RateLimitConfig config = new RateLimitConfig(key, algorithm, capacity, refillRate, windowSize, maxRequests);
            rateLimitConfigs.put(key, config);
            
            logger.info("限流器创建成功: {} (算法: {}, 容量: {}, 填充速率: {})", 
                       key, algorithm, capacity, refillRate);
            
            return true;
            
        } catch (Exception e) {
            logger.error("创建限流器失败: {}", key, e);
            alertManager.sendSystemErrorAlert("创建限流器失败", e.getMessage());
            return false;
        }
    }

    /**
     * 检查是否允许请求
     * 
     * @param key 限流键
     * @param tokens 请求的令牌数
     * @return 是否允许
     */
    public boolean isAllowed(String key, int tokens) {
        if (!rateLimitingEnabled) {
            return true;
        }

        try {
            totalRequests.incrementAndGet();
            
            RateLimiter rateLimiter = rateLimiters.get(key);
            if (rateLimiter == null) {
                // 使用默认配置创建限流器
                rateLimiter = createDefaultRateLimiter(key);
                if (rateLimiter == null) {
                    return true; // 如果创建失败，允许请求
                }
            }

            boolean allowed = rateLimiter.tryAcquire(tokens);
            
            if (allowed) {
                totalAllowedRequests.incrementAndGet();
            } else {
                totalRejectedRequests.incrementAndGet();
                totalRateLimitViolations.incrementAndGet();
                
                logger.debug("请求被限流拒绝: {} (请求令牌: {})", key, tokens);
            }
            
            return allowed;
            
        } catch (Exception e) {
            logger.error("检查限流状态失败: {}", key, e);
            return true; // 异常时允许请求
        }
    }

    /**
     * 检查是否允许请求（默认1个令牌）
     * 
     * @param key 限流键
     * @return 是否允许
     */
    public boolean isAllowed(String key) {
        return isAllowed(key, 1);
    }

    /**
     * 获取限流器状态
     * 
     * @param key 限流键
     * @return 限流器状态
     */
    public RateLimiterStatus getRateLimiterStatus(String key) {
        try {
            RateLimiter rateLimiter = rateLimiters.get(key);
            if (rateLimiter == null) {
                return null;
            }

            return rateLimiter.getStatus();
            
        } catch (Exception e) {
            logger.error("获取限流器状态失败: {}", key, e);
            return null;
        }
    }

    /**
     * 获取所有限流器状态
     * 
     * @return 限流器状态列表
     */
    public List<RateLimiterStatus> getAllRateLimiterStatus() {
        try {
            List<RateLimiterStatus> statusList = new ArrayList<>();
            for (RateLimiter rateLimiter : rateLimiters.values()) {
                statusList.add(rateLimiter.getStatus());
            }
            return statusList;
        } catch (Exception e) {
            logger.error("获取所有限流器状态失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 删除限流器
     * 
     * @param key 限流键
     * @return 是否删除成功
     */
    public boolean removeRateLimiter(String key) {
        try {
            RateLimiter removed = rateLimiters.remove(key);
            rateLimitConfigs.remove(key);
            
            if (removed != null) {
                logger.info("限流器删除成功: {}", key);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            logger.error("删除限流器失败: {}", key, e);
            return false;
        }
    }

    /**
     * 获取限流统计信息
     * 
     * @return 统计信息
     */
    public RateLimiterStatistics getStatistics() {
        return new RateLimiterStatistics(
            totalRequests.get(),
            totalAllowedRequests.get(),
            totalRejectedRequests.get(),
            totalRateLimitViolations.get(),
            rateLimiters.size(),
            rateLimitConfigs.size(),
            rateLimitingEnabled,
            defaultAlgorithm,
            defaultCapacity,
            defaultRefillRate,
            System.currentTimeMillis()
        );
    }

    /**
     * 设置限流配置
     * 
     * @param enabled 是否启用限流
     * @param defaultAlgorithm 默认算法
     * @param defaultCapacity 默认容量
     * @param defaultRefillRate 默认填充速率
     * @param defaultWindowSize 默认窗口大小
     * @param defaultMaxRequests 默认最大请求数
     */
    public void setConfiguration(boolean enabled, String defaultAlgorithm, int defaultCapacity,
                               int defaultRefillRate, int defaultWindowSize, int defaultMaxRequests) {
        this.rateLimitingEnabled = enabled;
        this.defaultAlgorithm = defaultAlgorithm;
        this.defaultCapacity = defaultCapacity;
        this.defaultRefillRate = defaultRefillRate;
        this.defaultWindowSize = defaultWindowSize;
        this.defaultMaxRequests = defaultMaxRequests;
        
        logger.info("限流配置已更新: 启用={}, 算法={}, 容量={}, 填充速率={}, 窗口大小={}, 最大请求={}", 
                   enabled, defaultAlgorithm, defaultCapacity, defaultRefillRate, defaultWindowSize, defaultMaxRequests);
    }

    /**
     * 创建限流器实例
     */
    private RateLimiter createRateLimiterInstance(String algorithm, int capacity, int refillRate, 
                                                int windowSize, int maxRequests) {
        switch (algorithm.toUpperCase()) {
            case "TOKEN_BUCKET":
                return new TokenBucketRateLimiter(capacity, refillRate);
            case "LEAKY_BUCKET":
                return new LeakyBucketRateLimiter(capacity, refillRate);
            case "SLIDING_WINDOW":
                return new SlidingWindowRateLimiter(windowSize, maxRequests);
            case "FIXED_WINDOW":
                return new FixedWindowRateLimiter(windowSize, maxRequests);
            default:
                logger.error("不支持的限流算法: {}", algorithm);
                return null;
        }
    }

    /**
     * 创建默认限流器
     */
    private RateLimiter createDefaultRateLimiter(String key) {
        try {
            return createRateLimiterInstance(defaultAlgorithm, defaultCapacity, defaultRefillRate, 
                defaultWindowSize, defaultMaxRequests);
        } catch (Exception e) {
            logger.error("创建默认限流器失败: {}", key, e);
            return null;
        }
    }

    /**
     * 启动限流监控任务
     */
    private void startRateLimitMonitoringTask() {
        scheduler.scheduleAtFixedRate(this::monitorRateLimiters, 
            0, 60, TimeUnit.SECONDS);
    }

    /**
     * 监控限流器
     */
    private void monitorRateLimiters() {
        try {
            // 这里可以实现限流器监控逻辑
            // 例如：清理过期的限流器、统计限流效果等
            logger.debug("监控限流器状态");
            
        } catch (Exception e) {
            logger.error("监控限流器失败", e);
        }
    }

    /**
     * 限流器接口
     */
    public interface RateLimiter {
        boolean tryAcquire(int tokens);
        RateLimiterStatus getStatus();
    }

    /**
     * 令牌桶限流器
     */
    public static class TokenBucketRateLimiter implements RateLimiter {
        private final int capacity;
        private final int refillRate;
        private final AtomicLong tokens;
        private final AtomicLong lastRefillTime;
        private final AtomicLong totalRequests;
        private final AtomicLong totalRejected;

        public TokenBucketRateLimiter(int capacity, int refillRate) {
            this.capacity = capacity;
            this.refillRate = refillRate;
            this.tokens = new AtomicLong(capacity);
            this.lastRefillTime = new AtomicLong(System.currentTimeMillis());
            this.totalRequests = new AtomicLong(0);
            this.totalRejected = new AtomicLong(0);
        }

        @Override
        public boolean tryAcquire(int tokens) {
            totalRequests.incrementAndGet();
            
            refillTokens();
            
            long currentTokens = this.tokens.get();
            if (currentTokens >= tokens) {
                this.tokens.addAndGet(-tokens);
                return true;
            } else {
                totalRejected.incrementAndGet();
                return false;
            }
        }

        @Override
        public RateLimiterStatus getStatus() {
            refillTokens();
            return new RateLimiterStatus(
                "TOKEN_BUCKET",
                capacity,
                refillRate,
                tokens.get(),
                totalRequests.get(),
                totalRejected.get(),
                System.currentTimeMillis()
            );
        }

        private void refillTokens() {
            long now = System.currentTimeMillis();
            long lastRefill = lastRefillTime.get();
            long timePassed = now - lastRefill;
            
            if (timePassed > 0) {
                long tokensToAdd = (timePassed * refillRate) / 1000;
                if (tokensToAdd > 0) {
                    long currentTokens = tokens.get();
                    long newTokens = Math.min(capacity, currentTokens + tokensToAdd);
                    tokens.set(newTokens);
                    lastRefillTime.set(now);
                }
            }
        }
    }

    /**
     * 漏桶限流器
     */
    public static class LeakyBucketRateLimiter implements RateLimiter {
        private final int capacity;
        private final int leakRate;
        private final AtomicLong currentLevel;
        private final AtomicLong lastLeakTime;
        private final AtomicLong totalRequests;
        private final AtomicLong totalRejected;

        public LeakyBucketRateLimiter(int capacity, int leakRate) {
            this.capacity = capacity;
            this.leakRate = leakRate;
            this.currentLevel = new AtomicLong(0);
            this.lastLeakTime = new AtomicLong(System.currentTimeMillis());
            this.totalRequests = new AtomicLong(0);
            this.totalRejected = new AtomicLong(0);
        }

        @Override
        public boolean tryAcquire(int tokens) {
            totalRequests.incrementAndGet();
            
            leakTokens();
            
            long currentLevel = this.currentLevel.get();
            if (currentLevel + tokens <= capacity) {
                this.currentLevel.addAndGet(tokens);
                return true;
            } else {
                totalRejected.incrementAndGet();
                return false;
            }
        }

        @Override
        public RateLimiterStatus getStatus() {
            leakTokens();
            return new RateLimiterStatus(
                "LEAKY_BUCKET",
                capacity,
                leakRate,
                currentLevel.get(),
                totalRequests.get(),
                totalRejected.get(),
                System.currentTimeMillis()
            );
        }

        private void leakTokens() {
            long now = System.currentTimeMillis();
            long lastLeak = lastLeakTime.get();
            long timePassed = now - lastLeak;
            
            if (timePassed > 0) {
                long tokensToLeak = (timePassed * leakRate) / 1000;
                if (tokensToLeak > 0) {
                    long currentLevel = this.currentLevel.get();
                    long newLevel = Math.max(0, currentLevel - tokensToLeak);
                    this.currentLevel.set(newLevel);
                    lastLeakTime.set(now);
                }
            }
        }
    }

    /**
     * 滑动窗口限流器
     */
    public static class SlidingWindowRateLimiter implements RateLimiter {
        private final int windowSizeSeconds;
        private final int maxRequests;
        private final Queue<Long> requestTimes;
        private final AtomicLong totalRequests;
        private final AtomicLong totalRejected;

        public SlidingWindowRateLimiter(int windowSizeSeconds, int maxRequests) {
            this.windowSizeSeconds = windowSizeSeconds;
            this.maxRequests = maxRequests;
            this.requestTimes = new ConcurrentLinkedQueue<>();
            this.totalRequests = new AtomicLong(0);
            this.totalRejected = new AtomicLong(0);
        }

        @Override
        public synchronized boolean tryAcquire(int tokens) {
            totalRequests.incrementAndGet();
            
            long now = System.currentTimeMillis();
            long windowStart = now - (windowSizeSeconds * 1000);
            
            // 清理过期的请求时间
            while (!requestTimes.isEmpty() && requestTimes.peek() < windowStart) {
                requestTimes.poll();
            }
            
            if (requestTimes.size() + tokens <= maxRequests) {
                for (int i = 0; i < tokens; i++) {
                    requestTimes.offer(now);
                }
                return true;
            } else {
                totalRejected.incrementAndGet();
                return false;
            }
        }

        @Override
        public RateLimiterStatus getStatus() {
            return new RateLimiterStatus(
                "SLIDING_WINDOW",
                maxRequests,
                windowSizeSeconds,
                requestTimes.size(),
                totalRequests.get(),
                totalRejected.get(),
                System.currentTimeMillis()
            );
        }
    }

    /**
     * 固定窗口限流器
     */
    public static class FixedWindowRateLimiter implements RateLimiter {
        private final int windowSizeSeconds;
        private final int maxRequests;
        private final AtomicLong currentRequests;
        private final AtomicLong windowStart;
        private final AtomicLong totalRequests;
        private final AtomicLong totalRejected;

        public FixedWindowRateLimiter(int windowSizeSeconds, int maxRequests) {
            this.windowSizeSeconds = windowSizeSeconds;
            this.maxRequests = maxRequests;
            this.currentRequests = new AtomicLong(0);
            this.windowStart = new AtomicLong(System.currentTimeMillis());
            this.totalRequests = new AtomicLong(0);
            this.totalRejected = new AtomicLong(0);
        }

        @Override
        public synchronized boolean tryAcquire(int tokens) {
            totalRequests.incrementAndGet();
            
            long now = System.currentTimeMillis();
            long currentWindowStart = windowStart.get();
            
            // 检查是否需要重置窗口
            if (now - currentWindowStart >= windowSizeSeconds * 1000) {
                currentRequests.set(0);
                windowStart.set(now);
            }
            
            long currentRequests = this.currentRequests.get();
            if (currentRequests + tokens <= maxRequests) {
                this.currentRequests.addAndGet(tokens);
                return true;
            } else {
                totalRejected.incrementAndGet();
                return false;
            }
        }

        @Override
        public RateLimiterStatus getStatus() {
            return new RateLimiterStatus(
                "FIXED_WINDOW",
                maxRequests,
                windowSizeSeconds,
                currentRequests.get(),
                totalRequests.get(),
                totalRejected.get(),
                System.currentTimeMillis()
            );
        }
    }

    /**
     * 限流器状态类
     */
    public static class RateLimiterStatus {
        private final String algorithm;
        private final int capacity;
        private final int rate;
        private final long currentLevel;
        private final long totalRequests;
        private final long totalRejected;
        private final long timestamp;

        public RateLimiterStatus(String algorithm, int capacity, int rate, long currentLevel,
                               long totalRequests, long totalRejected, long timestamp) {
            this.algorithm = algorithm;
            this.capacity = capacity;
            this.rate = rate;
            this.currentLevel = currentLevel;
            this.totalRequests = totalRequests;
            this.totalRejected = totalRejected;
            this.timestamp = timestamp;
        }

        // Getter方法
        public String getAlgorithm() { return algorithm; }
        public int getCapacity() { return capacity; }
        public int getRate() { return rate; }
        public long getCurrentLevel() { return currentLevel; }
        public long getTotalRequests() { return totalRequests; }
        public long getTotalRejected() { return totalRejected; }
        public long getTimestamp() { return timestamp; }
        
        public double getRejectionRate() {
            return totalRequests > 0 ? (double) totalRejected / totalRequests : 0.0;
        }
    }

    /**
     * 限流配置类
     */
    public static class RateLimitConfig {
        private final String key;
        private final String algorithm;
        private final int capacity;
        private final int refillRate;
        private final int windowSize;
        private final int maxRequests;

        public RateLimitConfig(String key, String algorithm, int capacity, int refillRate,
                             int windowSize, int maxRequests) {
            this.key = key;
            this.algorithm = algorithm;
            this.capacity = capacity;
            this.refillRate = refillRate;
            this.windowSize = windowSize;
            this.maxRequests = maxRequests;
        }

        // Getter方法
        public String getKey() { return key; }
        public String getAlgorithm() { return algorithm; }
        public int getCapacity() { return capacity; }
        public int getRefillRate() { return refillRate; }
        public int getWindowSize() { return windowSize; }
        public int getMaxRequests() { return maxRequests; }
    }

    /**
     * 限流统计信息类
     */
    public static class RateLimiterStatistics {
        private final long totalRequests;
        private final long totalAllowedRequests;
        private final long totalRejectedRequests;
        private final long totalRateLimitViolations;
        private final int activeRateLimiters;
        private final int totalConfigs;
        private final boolean rateLimitingEnabled;
        private final String defaultAlgorithm;
        private final int defaultCapacity;
        private final int defaultRefillRate;
        private final long timestamp;

        public RateLimiterStatistics(long totalRequests, long totalAllowedRequests, long totalRejectedRequests,
                                   long totalRateLimitViolations, int activeRateLimiters, int totalConfigs,
                                   boolean rateLimitingEnabled, String defaultAlgorithm, int defaultCapacity,
                                   int defaultRefillRate, long timestamp) {
            this.totalRequests = totalRequests;
            this.totalAllowedRequests = totalAllowedRequests;
            this.totalRejectedRequests = totalRejectedRequests;
            this.totalRateLimitViolations = totalRateLimitViolations;
            this.activeRateLimiters = activeRateLimiters;
            this.totalConfigs = totalConfigs;
            this.rateLimitingEnabled = rateLimitingEnabled;
            this.defaultAlgorithm = defaultAlgorithm;
            this.defaultCapacity = defaultCapacity;
            this.defaultRefillRate = defaultRefillRate;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getTotalRequests() { return totalRequests; }
        public long getTotalAllowedRequests() { return totalAllowedRequests; }
        public long getTotalRejectedRequests() { return totalRejectedRequests; }
        public long getTotalRateLimitViolations() { return totalRateLimitViolations; }
        public int getActiveRateLimiters() { return activeRateLimiters; }
        public int getTotalConfigs() { return totalConfigs; }
        public boolean isRateLimitingEnabled() { return rateLimitingEnabled; }
        public String getDefaultAlgorithm() { return defaultAlgorithm; }
        public int getDefaultCapacity() { return defaultCapacity; }
        public int getDefaultRefillRate() { return defaultRefillRate; }
        public long getTimestamp() { return timestamp; }
        
        public double getRejectionRate() {
            return totalRequests > 0 ? (double) totalRejectedRequests / totalRequests : 0.0;
        }
    }
}
